package cn.yunyichina.provider.order.service.impl;

import cn.yunyichina.provider.framework.dubbo.service.AlipayService;
import cn.yunyichina.provider.framework.dubbo.service.PayService;
import cn.yunyichina.provider.iface.entity.alipay.Alipay;
import cn.yunyichina.provider.iface.entity.alipay.AlipayFacepayMedicalCardQueryRequest;
import cn.yunyichina.provider.iface.entity.alipay.AlipayFacepayMedicalCardQueryResponse;
import cn.yunyichina.provider.iface.entity.base.OrderExtVo;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.order.facepay.FacepayRequestVO;
import cn.yunyichina.provider.iface.entity.order.facepay.FacepayResponseVO;
import cn.yunyichina.provider.iface.entity.pay.PayCode;
import cn.yunyichina.provider.order.constant.*;
import cn.yunyichina.provider.order.service.BaseFacepayService;
import cn.yunyichina.provider.order.service.FacepayService;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.json.Jackson;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * 当面付
 * Created by Lullaby on 2017/4/25.
 */
@Service
public class FacepayServiceImpl extends BaseFacepayService implements FacepayService {

    private static final Logger logger = LoggerFactory.getLogger(FacepayServiceImpl.class);

    /**
     * 对外当面付接口
     *
     * @param params
     * @return
     */
    public ResCommon<FacepayResponseVO> openapiFacepay(String params) {
        logger.info("FacepayServiceImpl.openapiFacepay.params -> {}", params);

        FacepayRequestVO requestVO = JSON.parseObject(params, FacepayRequestVO.class);
        logger.info("FacepayServiceImpl.openapiFacepay.requestVO -> {}", Jackson.toJson(requestVO));

        Integer payMode = requestVO.getPayMode();
        if (StringUtils.isEmpty(payMode)) {
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.PAY_MODE_NULL.getCode(),
                    ResponseEnum.PAY_MODE_NULL.getMessage()
            );
        }

        if (PayCode.ALIPAYBARPAY.getMode() == payMode) {
            return alipayBarPay(requestVO);
        } else if (PayCode.WXMICROPAY.getMode() == payMode) {
            return wechatMicroPay(params);
        }

        return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                ResponseEnum.PAY_MODE_NOT_SUPPORT.getCode(),
                ResponseEnum.PAY_MODE_NOT_SUPPORT.getMessage()
        );
    }

    /**
     * 微信刷卡支付
     *
     * @param params
     * @return
     */
    private ResCommon<FacepayResponseVO> wechatMicroPay(String params) {
        FacepayRequestVO request = JSON.parseObject(params, FacepayRequestVO.class);

        if (!checkSelfFacePayParams(request))
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.Common.INVALID.getCode(),
                    ResponseEnum.Common.INVALID.getMessage()
            );

        OrderExtVo orderExtVo = generateOrder(request);
        logger.info("FacepayServiceImpl.wechatMicroPay.orderExtVo -> {}", JSON.toJSONString(orderExtVo));

        if (orderExtVo == null)
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_INSERT_FAILURE.getCode(),
                    ResponseEnum.ORDER_INSERT_FAILURE.getMessage()
            );

        String payRequest = buildSelfFacePayParams(request, orderExtVo);
        logger.info("FacepayServiceImpl.wechatMicroPay.payRequest -> {}", payRequest);

        ResponseObject payResponse = PayService.callUnderlineFromInternalObject(MethodRouter.YYT_PAY_PAY_UNIFIED, payRequest);
        logger.info("FacepayServiceImpl.wechatMicroPay.payResponse -> {}", JsonUtils.toJsonString(payResponse));

        Map payResult = JsonUtils.parseObject(payResponse.getResultObject(), Map.class);
        logger.info("FacepayServiceImpl.wechatMicroPay.payResult -> {}", JsonUtils.toJsonString(payResult));

        if (payResponse.isSuccess()) {
            ResCommon<FacepayResponseVO> resCommon = paySucceed(orderExtVo, payResult, request.getPayMode());
            logger.info("FacepayServiceImpl.wechatMicroPay.response -> {}", JSON.toJSONString(resCommon));
            return resCommon;
        }

        String orderId = orderExtVo.getId();
        String resultCode = payResponse.getResultCode();
        String resultMessage = payResponse.getResultMessage();
        if ("5000".equals(resultCode)) {
            updateOrderByStatus(orderId, OrderConst.OrderStatus.EXCEPTION.getStatus(), OrderConst.PayStatus.PAY_FAILED.getStatus());

            return payFailed(ResponseEnum.ORDER_FACEPAY_MANUAL.getCode(), ResponseEnum.ORDER_FACEPAY_MANUAL.getMessage());
        } else if ("5042".equals(resultCode)) {
            updateOrderByStatus(orderId, OrderConst.OrderStatus.CANCELED.getStatus(), OrderConst.PayStatus.PAY_FAILED.getStatus());

            return payFailed(ResponseEnum.ORDER_FACEPAY_REVERSED.getCode(), ResponseEnum.ORDER_FACEPAY_REVERSED.getMessage());
        } else {
            updateOrderByStatus(orderId, OrderConst.OrderStatus.FAILED.getStatus(), OrderConst.PayStatus.PAY_FAILED.getStatus());

            if (payResult != null) {
                String code = StringUtils.isEmpty(payResult.get("err_code")) ? (String) payResult.get("return_code") : (String) payResult.get("err_code");
                String msg = StringUtils.isEmpty(payResult.get("err_code_des")) ? (String) payResult.get("return_msg") : (String) payResult.get("err_code_des");

                return payFailed(StringUtils.isEmpty(code) ? resultCode : code, StringUtils.isEmpty(msg) ? resultMessage : msg);
            } else {
                return payFailed(resultCode, resultMessage);
            }
        }
    }

    /**
     * 支付宝医疗支付当面付
     *
     * @param requestVO
     * @return
     */
    private ResCommon<FacepayResponseVO> alipayBarPay(FacepayRequestVO requestVO) {
        String isInsurance = requestVO.getCanUseInsurance();
        String orderType = requestVO.getOrderType();
        logger.info("FacepayServiceImpl.alipayBarPay.isInsurance & orderType -> {}, {}", isInsurance, orderType);

        try {
            if (OrderConst.INSURANCE_ORDER.equals(isInsurance)) {
                if (OrderType.REGISTRATION.getCode() == Byte.valueOf(orderType)) {
                    return insuranceAlipayFacepayRegistration(requestVO);
                }

                return insuranceAlipayFacepay(requestVO);
            }

            return selfAlipayFacepay(requestVO);
        } catch (Exception e) {
            logger.error("FacepayServiceImpl.alipayBarPay.exception", e);
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_FACEPAY_EXCEPTION.getCode(),
                    ResponseEnum.ORDER_FACEPAY_EXCEPTION.getMessage()
            );
        }
    }

    /**
     * 支付宝自费当面付
     *
     * @param request
     * @return
     */
    private ResCommon<FacepayResponseVO> selfAlipayFacepay(FacepayRequestVO request) {
        if (!checkSelfFacePayParams(request))
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.Common.INVALID.getCode(),
                    ResponseEnum.Common.INVALID.getMessage()
            );

        OrderExtVo orderExtVo = generateOrder(request);
        logger.info("FacepayServiceImpl.selfAlipayFacepay.orderExtVo -> {}", orderExtVo);

        if (orderExtVo == null)
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_INSERT_FAILURE.getCode(),
                    ResponseEnum.ORDER_INSERT_FAILURE.getMessage()
            );

        String payRequest = buildSelfFacePayParams(request, orderExtVo);
        logger.info("FacepayServiceImpl.selfAlipayFacepay.payRequest -> {}", payRequest);

        ResponseObject payResponse = PayService.callUnderlineFromInternalObject(MethodRouter.YYT_PAY_PAY_UNIFIED, payRequest);
        logger.info("FacepayServiceImpl.selfAlipayFacepay.payResponse -> {}", JsonUtils.toJsonString(payResponse));

        if (payResponse.isSuccess()) {
            Map payResult = JsonUtils.parseObject(payResponse.getResultObject(), Map.class);
            logger.info("FacepayServiceImpl.selfAlipayFacepay.payResult -> {}", JsonUtils.toJsonString(payResult));
            return paySucceed(orderExtVo, payResult, request.getPayMode());
        }

        String orderId = orderExtVo.getId();
        String resultCode = payResponse.getResultCode();
        String resultMessage = payResponse.getResultMessage();
        if ("5000".equals(resultCode)) {
            updateOrderByStatus(orderId, OrderConst.OrderStatus.EXCEPTION.getStatus(), OrderConst.PayStatus.PAY_FAILED.getStatus());

            return payFailed(ResponseEnum.ORDER_FACEPAY_MANUAL.getCode(), ResponseEnum.ORDER_FACEPAY_MANUAL.getMessage());
        } else if ("5042".equals(resultCode)) {
            updateOrderByStatus(orderId, OrderConst.OrderStatus.CANCELED.getStatus(), OrderConst.PayStatus.PAY_FAILED.getStatus());

            return payFailed(ResponseEnum.ORDER_FACEPAY_REVERSED.getCode(), ResponseEnum.ORDER_FACEPAY_REVERSED.getMessage());
        } else {
            updateOrderByStatus(orderId, OrderConst.OrderStatus.FAILED.getStatus(), OrderConst.PayStatus.PAY_FAILED.getStatus());

            return payFailed(resultCode, resultMessage);
        }
    }

    /**
     * 支付宝医保当面付
     *
     * @param request
     * @return
     * @throws Exception
     */
    private ResCommon<FacepayResponseVO> insuranceAlipayFacepay(FacepayRequestVO request) throws Exception {
        if (!checkInsuranceFacePayParams(request))
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.Common.INVALID.getCode(),
                    ResponseEnum.Common.INVALID.getMessage()
            );

        AlipayFacepayMedicalCardQueryRequest queryRequest = buildAlipayFacepayMedicalCardQueryParameters(request);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepay.queryRequest -> {}", JsonUtils.toJsonString(queryRequest));

        ResCommon<AlipayFacepayMedicalCardQueryResponse> queryResponse = AlipayService.getAlipayClient().queryAlipayFacepayMedicare(queryRequest);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepay.queryResponse -> {}", JsonUtils.toJsonString(queryResponse));

        if (!queryResponse.isSuccess())
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_MEDICAL_CARD_QUERY_FAILURE.getCode(),
                    ResponseEnum.ORDER_MEDICAL_CARD_QUERY_FAILURE.getMessage()
            );

        OrderExtVo orderExtVo = generateOrder(request);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepay.orderExtVo -> {}", JsonUtils.toJsonString(orderExtVo));

        if (orderExtVo == null)
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_INSERT_FAILURE.getCode(),
                    ResponseEnum.ORDER_INSERT_FAILURE.getMessage()
            );

        String payRequest = buildInsuranceFacePayParams(request, orderExtVo);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepay.payRequest -> {}", payRequest);

        ResponseObject payResponse = PayService.callUnderlineFromInternalObject(MethodRouter.YYT_PAY_PAY_UNIFIED, payRequest);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepay.payResponse -> {}", JsonUtils.toJsonString(payResponse));

        if (!payResponse.isSuccess())
            return payFailed(payResponse.getResultCode(), payResponse.getResultMessage());

        Map payResult = JsonUtils.parseObject(payResponse.getResultObject(), Map.class);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepay.payResult -> {}", JsonUtils.toJsonString(payResult));

        assert payResult != null;
        String code = (String) payResult.get("code");
        String msg = (String) payResult.get("msg");
        if (Alipay.SUCCESS_CODE.equals(code)) {
            return paySucceed(orderExtVo, payResult, request.getPayMode());
        }

        return payFailed(code, msg);
    }

    /**
     * 支付宝医保挂号当面付
     *
     * @param request
     * @return
     * @throws Exception
     */
    private ResCommon<FacepayResponseVO> insuranceAlipayFacepayRegistration(FacepayRequestVO request) throws Exception {
        if (!checkInsuranceFacePayRegistrationParams(request))
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.Common.INVALID.getCode(),
                    ResponseEnum.Common.INVALID.getMessage()
            );
        AlipayFacepayMedicalCardQueryRequest queryRequest = buildAlipayFacepayMedicalCardQueryParameters(request);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepayRegistration.queryRequest -> {}", JsonUtils.toJsonString(queryRequest));

        ResCommon<AlipayFacepayMedicalCardQueryResponse> queryResponse = AlipayService.getAlipayClient().queryAlipayFacepayMedicare(queryRequest);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepayRegistration.queryResponse -> {}", JsonUtils.toJsonString(queryResponse));

        if (!queryResponse.isSuccess()) {
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_MEDICAL_CARD_QUERY_FAILURE.getCode(),
                    ResponseEnum.ORDER_MEDICAL_CARD_QUERY_FAILURE.getMessage()
            );
        }

        OrderExtVo orderExtVo = generateOrder(request);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepayRegistration.orderExtVo -> {}", JsonUtils.toJsonString(orderExtVo));

        if (orderExtVo == null)
            return new ResCommon<FacepayResponseVO>().buildResultCodeAndMessage(
                    ResponseEnum.ORDER_INSERT_FAILURE.getCode(),
                    ResponseEnum.ORDER_INSERT_FAILURE.getMessage()
            );

        String payRequest = buildInsuranceFacePayRegistrationParams(request, orderExtVo);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepayRegistration.payRequest -> {}", payRequest);

        ResponseObject payResponse = PayService.callUnderlineFromInternalObject(MethodRouter.YYT_PAY_PAY_UNIFIED, payRequest);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepayRegistration.payResponse -> {}", JsonUtils.toJsonString(payResponse));

        if (!payResponse.isSuccess())
            return payFailed(payResponse.getResultCode(), payResponse.getResultMessage());

        Map payResult = JsonUtils.parseObject(payResponse.getResultObject(), Map.class);
        logger.info("FacepayServiceImpl.insuranceAlipayFacepayRegistration.payResult -> {}", JsonUtils.toJsonString(payResult));

        assert payResult != null;
        String code = (String) payResult.get("code");
        String msg = (String) payResult.get("msg");
        if (Alipay.SUCCESS_CODE.equals(code)) {
            return paySucceed(orderExtVo, payResult, request.getPayMode());
        }

        return payFailed(code, msg);
    }

    /**
     * 支付成功逻辑处理
     *
     * @param orderExtVo
     * @param payResult
     * @return
     */
    private ResCommon<FacepayResponseVO> paySucceed(OrderExtVo orderExtVo, Map payResult, int payMode) {
        updateOrderBySuccess(orderExtVo.getId(), payResult, payMode);

        if (FacePayMode.ALIPAYBARPAY.getCode() == payMode) {
            return new ResCommon<FacepayResponseVO>().buildResult(getFacepayResponseVO(
                    orderExtVo.getHisOrderNo(),
                    orderExtVo.getOrderNo(),
                    (String) payResult.get("trade_no"),
                    (String) payResult.get("buyer_user_id"),
                    (String) payResult.get("buyer_logon_id")
            ));
        } else if (FacePayMode.WXMICROPAY.getCode() == payMode) {
            return new ResCommon<FacepayResponseVO>().buildResult(getFacepayResponseVO(
                    orderExtVo.getHisOrderNo(),
                    orderExtVo.getOrderNo(),
                    (String) payResult.get("transaction_id"),
                    (String) payResult.get("openid"),
                    (String) payResult.get("openid")
            ));
        }

        return null;
    }

    /**
     * 支付失败返回信息
     *
     * @param errcode
     * @param errmsg
     * @return
     */
    private ResCommon<FacepayResponseVO> payFailed(String errcode, String errmsg) {
        ResCommon<FacepayResponseVO> resCommon = new ResCommon<>();
        resCommon.setResultCodeAndMessage(
                ResponseEnum.ORDER_FACEPAY_FAILURE.getCode(),
                ResponseEnum.ORDER_FACEPAY_FAILURE.getMessage());
        resCommon.setResult(new FacepayResponseVO().setErrcode(errcode).setErrmsg(errmsg));

        return resCommon;
    }

}
